home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / strings.swg / 0111_Neat Percentage Compare.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-05-26  |  7.3 KB  |  214 lines

  1. {
  2.     Here is a function some of you may find useful, it tries to find
  3. misspellings such as "Hello World" and "Hello Wolrd" by comparing 2 strings
  4. and returning a percent base of 3 tests of how close they match...
  5. Lemme know if you know of a way to improve upon this.
  6. }
  7.  
  8. {$B-,V-,S-,R-,I-,A+}       { for speed }
  9.  
  10. uses dos, crt;
  11.  
  12. var
  13.    string_a  : string;
  14.    string_b  : string;    { for the 5 line example at the bottom }
  15.  
  16.  
  17.  
  18.  
  19. {------------------------------------------------------------------------}
  20. { 'InStr' -For use with StrMatcher.                                      }
  21. {                                                                        }
  22. {     InStr is just like POS except you may specify a starting position. }
  23. {                                                                        }
  24. {------------------------------------------------------------------------}
  25. function InStr(index : byte; var string1, string2 : string) : byte;
  26. var
  27.    tempstring : string;
  28. begin
  29.    tempstring := copy(string2, index, length(string2)-index);
  30.    InStr := pos(string1, tempstring) + index - 1;
  31. end;
  32.  
  33.  
  34.  
  35.  
  36. {------------------------------------------------------------------------}
  37. { 'StrMatcher' -String Matching Procedure, Written by Kevin Currie, '94  }
  38. {                                                                        }
  39. {     StrMatcher accepts two pointers and (w/o case sensitivity) tries   }
  40. {  to determine how well their strings match.  It then returns a percent }
  41. {  value of its tests into a shortint.                                   }
  42. {                                                                        }
  43. {------------------------------------------------------------------------}
  44. function strmatcher(var string1, string2 : string) : shortint;
  45. var
  46.    strn1, strn2, tmpstr1, tmpstr2 : string;
  47.    len1, len2, short : byte;
  48.    stest, which, loop : longint;
  49.    postest1, postest2 : integer;
  50.    perc1, perc2, perc3 : real;
  51.    retval : shortint;
  52. label
  53.    string_match_100,
  54.    string_match_len;
  55. begin
  56.    { ---===> Don't yell at me about the goto's, they are there for speed  }
  57.    {         and clarity.  (It's clearer than a HUGE block under an if)   }
  58.  
  59.    { ---===> UpperCase the strings to see if that is where the difference }
  60.    {         lies, and also to make the other comparisons easier.         }
  61.  
  62.    strn1 := string1;
  63.    len1 := length(string1);                 { I make backup copies        }
  64.    for loop := 1 to len1 do                 { because var is just another }
  65.       strn1[loop] := upcase(strn1[loop]);   { way of saying pointer...    }
  66.    strn2 := string2;                        { In other words if I didn't  }
  67.    len2 := length(string2);                 { I would modify the original }
  68.    for loop := 1 to len2 do                 { strings...                  }
  69.       strn2[loop] := upcase(strn2[loop]);
  70.  
  71.  
  72.    { ---===> See of the capitalized strings match }
  73.    if (strn1 = strn2) then
  74.    begin
  75.       retval := 100;
  76.       goto string_match_100;
  77.    end; {if}
  78.  
  79.    { ---===> Test 1 checks the occurence of chars from string1     }
  80.    {         against the chars in string2                          }
  81.    stest := 0;
  82.    for loop := 1 to len1 do
  83.    begin
  84.       tmpstr1 := strn1[loop];
  85.       if (pos(tmpstr1, strn2) > 0) then inc(stest);
  86.    end; {for}
  87.    perc2 := stest / len1;
  88.    stest := 0;
  89.    for loop := 1 to len2 do
  90.    begin
  91.       tmpstr2 := strn2[loop];
  92.       if (pos(tmpstr2, strn1) > 0) then inc(stest);
  93.    end; {for}
  94.    perc3 := stest / len2;
  95.    perc1 := (perc3 + perc2) / 2;
  96.    if (perc1 < 0) then perc1 := 0;
  97.  
  98.    { ---===> Test 2 Adds the Values of all the charcters in the    }
  99.    {         string and then takes a percent of 1 vs 2.            }
  100.  
  101.    stest := 0;
  102.    which := 0;
  103.    for loop := 1 to len1 do                { ---===> the shl 4's and the  }
  104.       stest := stest + ord(strn1[loop]);   {         shr 2's below are to }
  105.    stest := stest shl 4;                   {         add some more weight }
  106.    for loop := 1 to len2 do                {         to the difference.   }
  107.       which := which + ord(strn2[loop]);
  108.    which := which shl 4;
  109.    loop := stest shr 2;
  110.    if (which > stest) then loop := which shr 2;
  111.    perc2 := 1 - (abs(stest - which) / loop);
  112.    if (perc2 < 0) then perc2 := 0;
  113.  
  114.    { ---===> Test 3 checks the character position differences between  }
  115.    {         the two strings.                                          }
  116.    {                                                                   }
  117.    {         NOTE:  A string being shorter than another can cause this }
  118.    {                test to fail quite badly so null characters are    }
  119.    {                placed in the shorter string where there are char  }
  120.    {                mismatches until the strings are equal in length.  }
  121.  
  122.    if (len1 = len2) then goto string_match_len;
  123.  
  124.    tmpstr1 := '';
  125.    tmpstr2 := '';
  126.       loop :=  1;
  127.  
  128.    if (len1 > len2) then
  129.    begin
  130.       short := len1 - len2;
  131.       which := 2;
  132.    end else
  133.    begin
  134.       short := len2 - len1;
  135.       which := 1;
  136.    end; {if/else}
  137.  
  138.    while (short <> 0) do
  139.    begin
  140.       if (strn1[loop] = strn2[loop]) then
  141.       begin
  142.          case which of
  143.             1:   tmpstr1 := tmpstr1 + strn2[loop];
  144.             2:   tmpstr1 := tmpstr1 + strn1[loop];
  145.          end; {case}
  146.       end else
  147.       begin
  148.          case which of
  149.             1:
  150.             begin
  151.                tmpstr1 := tmpstr1 + #0;
  152.                tmpstr2 := copy(strn1, loop, (len1-loop)+1);
  153.                  strn1 := concat(tmpstr1, tmpstr2);
  154.                dec(short);
  155.             end; {case1}
  156.             2:
  157.             begin
  158.                tmpstr1 := tmpstr1 + #0;
  159.                tmpstr2 := copy(strn2, loop, (len2-loop)+1);
  160.                  strn2 := concat(tmpstr1, tmpstr2);
  161.                dec(short);
  162.             end; {case2}
  163.          end; {case}
  164.       end; {if/else}
  165.       inc(loop);
  166.    end; {while}
  167.  
  168.    len1 := length(strn1);      { ---===> Reset these after the loop that }
  169.    len2 := length(strn2);      {         makes them the same length.     }
  170.  
  171.  string_match_len: {label}
  172.  
  173.    { ---===> Now that we have the string lengths the same lets check the }
  174.    {         character positions.                                        }
  175.  
  176.    stest := 0;
  177.    for loop := 1 to len1 do
  178.       stest := stest + loop + loop - 1;
  179.    which := stest;
  180.    for loop := 1 to len1 do
  181.    begin
  182.       tmpstr1  := strn1[loop];
  183.       tmpstr2  := strn2[loop];
  184.       postest1 :=  len1 - abs(instr(loop, tmpstr2, strn1));
  185.       postest2 :=  len2 - abs(instr(loop, tmpstr2, strn2));
  186.       stest    := stest - (postest1 + postest2);
  187.    end;
  188.    stest := which - abs(stest);
  189.    which := which + (len1 div 2);
  190.    perc3 := stest / which;
  191.    if (perc3 < 0) then perc3 := 0;
  192.  
  193.    { ---===> Average the results of the 3 tests.         }
  194.    {         They are weighted hence the 80, 10 and 10.  }
  195.  
  196.    retval := trunc(((perc1 * 80) + (perc2 * 10) + (perc3 * 10)));
  197.  
  198. string_match_100: {label}
  199.  
  200.    strmatcher := retval; { ---===> Return Percent Difference. }
  201. end; {StrMatcher}
  202.  
  203.  
  204.  
  205.  
  206. begin       { ---===> Stupid 5 line example. }
  207.    clrscr;
  208.    string_a := 'Hello World';
  209.    string_b := 'Hello Wolrd';
  210.    writeln('String Match Percent:', strmatcher(string_a, string_b):5);
  211.    readln;
  212. end. {main} { ---===> hey, I use C also :-)  }
  213.  
  214.